#include "stdafx.h"
#include "Camera.h"

#include "../util/Geometry.h"

namespace WindGE
{
	Camera::Camera()
		: Component()
		, position_(0.0f, 0.0f, 0.0f)
		, target_(0.0f, 0.0f, 0.0f)
		, look_(0.0f, 0.0f, 1.0f)
		, up_(0.0f, 1.0f, 0.0f)
		, right_(1.0f, 0.0f, 0.0f)
	{
		XMMATRIX I = XMMatrixIdentity();
		XMStoreFloat4x4(&view_matrix_, I);
		XMStoreFloat4x4(&proj_matrix_, I);
		
		frustum_ = std::make_shared<Frustum>();
	}

	Camera::Camera(GameObjectPtr gameObject)
		: Component(gameObject)
		, position_(0.0f, 0.0f, 0.0f)
		, target_(0.0f, 0.0f, 0.0f)
		, look_(0.0f, 0.0f, 1.0f)
		, up_(0.0f, 1.0f, 0.0f)
		, right_(1.0f, 0.0f, 0.0f)
	{
		XMMATRIX I = XMMatrixIdentity();
		XMStoreFloat4x4(&view_matrix_, I);
		XMStoreFloat4x4(&proj_matrix_, I);

		frustum_ = std::make_shared<Frustum>();
	}

	void Camera::update_view_matrix()
	{
		XMVECTOR look = XMLoadFloat3(&look_);
		XMVECTOR right = XMLoadFloat3(&right_);
		XMVECTOR up = XMLoadFloat3(&up_);

		XMVECTOR pos = XMLoadFloat3(&position_);

		look = XMVector3Normalize(look);

		up = XMVector3Cross(look, right);
		up = XMVector3Normalize(up);

		right = XMVector3Cross(up, look);
		right = XMVector3Normalize(right);

		float x = -XMVectorGetX(XMVector3Dot(right, pos));
		float y = -XMVectorGetX(XMVector3Dot(up, pos));
		float z = -XMVectorGetX(XMVector3Dot(look, pos));

		XMStoreFloat3(&look_, look);
		XMStoreFloat3(&right_, right);
		XMStoreFloat3(&up_, up);
		XMStoreFloat3(&position_, pos);

		view_matrix_(0, 0) = right_.x;
		view_matrix_(0, 1) = up_.x;
		view_matrix_(0, 2) = look_.x;
		view_matrix_(0, 3) = 0.0f;

		view_matrix_(1, 0) = right_.y;
		view_matrix_(1, 1) = up_.y;
		view_matrix_(1, 2) = look_.y;
		view_matrix_(1, 3) = 0.0f;

		view_matrix_(2, 0) = right_.z;
		view_matrix_(2, 1) = up_.z;
		view_matrix_(2, 2) = look_.z;
		view_matrix_(2, 3) = 0.0f;

		view_matrix_(3, 0) = x;
		view_matrix_(3, 1) = y;
		view_matrix_(3, 2) = z;
		view_matrix_(3, 3) = 1.0f;
	}

	void Camera::update()
	{
		update_view_matrix();

		frustum_->extractFromMatrix(view_matrix()*proj_matrix());
	}
}


